
#include "FlyweightFactory.h"
#include "FlyweightA.h"
#include "FlyweightB.h"
#include <iostream>

using namespace npFlyweight;
using namespace std;


FlyweightFactory::FlyweightFactory() // class inheritance
{
    //To initialize data member;
    this->flyweights.insert(pair<int, Flyweight*>(0, new FlyweightA()));
    this->flyweights.insert(pair<int, Flyweight*>(1, new FlyweightB()));
}

FlyweightFactory::~FlyweightFactory()
{
    //To delete dynamic data member
    this->clearFlyweights();
}

FlyweightFactory::FlyweightFactory(const FlyweightFactory& cpy) // class inheritance
{
    //To copy data member
    this->clearFlyweights();
    for (auto i = cpy.flyweights.begin(); i != cpy.flyweights.end(); i++)
    {
        this->flyweights.insert(
            pair<int, Flyweight*>(
                i->first,
                i->second->clone()
            )
        );
    }
}

FlyweightFactory& FlyweightFactory::operator=(const FlyweightFactory& asn)
{
    if (this == &asn)
    {
        return *this;
    }
    else
    {
        //To invoke base class operator=
        
        //To assign data member, note to delete dynamic member if exists.
        this->clearFlyweights();
        for (auto i = asn.flyweights.begin(); i != asn.flyweights.end(); i++)
        {
            this->flyweights.insert(
                pair<int, Flyweight*>(
                    i->first,
                    i->second->clone()
                )
            );
        }
        
        return *this;
    }
}

FlyweightFactory::FlyweightFactory(FlyweightFactory&& mov) noexcept // class inheritance
{
    //to move data
    this->clearFlyweights();
    this->flyweights.swap(mov.flyweights);
}

FlyweightFactory& FlyweightFactory::operator=(FlyweightFactory&& mva) noexcept
{
    if (this == &mva)
    {
        return *this;
    }
    else
    {
        //to inform base class to move data
        
        // to move data
        this->clearFlyweights();
        this->flyweights.swap(mva.flyweights);

        return *this;
    }
}

FlyweightFactory* FlyweightFactory::clone() const
{
    //return new
    return new FlyweightFactory(*this);
}

//other constructors

//public methods
Flyweight& FlyweightFactory::getFlyweight(int n) const throw(out_of_range)
{
    return *this->flyweights.at(n);
}

//protected methods

//private methods
void FlyweightFactory::clearFlyweights()
{
    for (auto i = this->flyweights.begin(); i != this->flyweights.end(); i++)
    {
        delete i->second;
    }
    map<int, Flyweight*>().swap(this->flyweights);
}

//others
const FlyweightFactory FlyweightFactory::singleton;

const FlyweightFactory& FlyweightFactory::getInst()
{
    return singleton;
}
